package net.homelinux.chaoswg.io.renga.krypto.datatypes.vectors;

import java.math.BigInteger;
import java.util.Iterator;

import net.homelinux.chaoswg.io.renga.krypto.datatypes.CryptographicalType;

/**
 * BitVector (as bitset does not work correct in some cases) 
 * @author martin
 *
 */
public class BitVector implements CryptographicalType, Iterable<Boolean> {
    private final boolean[] field;
    
    public BitVector () {
        this(32);
    }
    
    public BitVector(final int size) {
        field = new boolean [size];

        for (int i = 0; i < field.length; ++i) {
            this.field[i] = false;
        }
    }
    
    public BitVector (final BitVector bv) {
        field = new boolean [bv.getSize()];
        for (int i = 0; i < field.length; ++i) {
            this.field[i] = bv.get(i); 
        }
    }
    
    public final int getSize () {
        return field.length;
    }
    
    public final boolean get (final int i) {
        return field[i];
    }
    
    public final void set (final int i) {
        this.field[i] = true;
    }
    
    public final void set (final int i, final boolean b) {
        this.field[i] = b;
    }
    
    public final void unset (final int i) {
        this.field[i] = false;
    }
    
    public final Iterator<Boolean> iterator () {
        final Iterator<Boolean> iter = new Iterator<Boolean> () {
            private int i = 0;
            
            public final boolean hasNext () {
                return i < field.length; 
            }
            
            public final Boolean next () {
                return field[i++];
            }
            
            public final void remove () {
                throw new UnsupportedOperationException ();
            }
        };
        
        return iter;
    }
    
    public String toString () {
        return toHexString();
    }
    
    private final BigInteger toBigInteger () {
        final int length = this.getSize();
        BigInteger  tmp = new BigInteger ("0");
        for (int i=0; i < length; ++i) {
            if (this.get(i)) {
                tmp = tmp.setBit((length - 1-i));
            }
        }
        return tmp;
    }

    public final String toBinaryString () {
        StringBuffer sb = new StringBuffer ();
        
        for (int i = 0; i < this.field.length; ++i) {
            sb.append (this.field[i] ? 1 : 0);
        }
        
        return sb.toString();
    }
    
    public final String toOctetString () {
        return toBigInteger().toString(8);
    }
    
    public final String toDecimalString () {
        return toBigInteger().toString(8);
    }
    
    public final String toHexString () {
        return toBigInteger().toString(16);
    }
}
